﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using GmailMetroNotifier.Client.Business;
using GmailMetroNotifier.Client.Common;
using GmailMetroNotifier.Client.Properties;
using GmailMetroNotifier.Client.UIP;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

namespace GmailMetroNotifier.Client.UI
{
    /// <summary>
    /// Application main form, hidden by default.
    /// </summary>
    public partial class MainForm : Form
    {
        private bool _isCheckMailInProgress = false;

        private NotificationManager _notificationManager = null;

        private ICredentialsManager _credentialsManager = null;

        private IGmailManager _gmailManager = null;

        private Action<NotificationResult> _toastActionHandler = result =>
            {
                if (result == NotificationResult.OK)
                {
                    BrowseGmail();
                }
            };

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this._notificationManager = new NotificationManager(
                new DesktopNotificationProvider(),
                new ToastNotificationProvider(),
                new NotifyIconNotificationProvider(this.trayNotifyIcon));

            this._credentialsManager = new CredentialsManager();

            this._gmailManager = new GmailManager();

            this._gmailManager.AuthenticationFailed += new WeakEventHandler<object, AuthenticationFailedEventArgs>(GmailManager_AuthenticationFailed).Handler;

            this._gmailManager.AuthenticationSucceeded += new WeakEventHandler<object, AuthenticationSucceededEventArgs>(GmailManager_AuthenticationSucceeded).Handler;

            if (!Debugger.IsAttached)
            {
                this.ShowInTaskbar = false;

                this.FormBorderStyle = FormBorderStyle.FixedToolWindow;

                this.StartPosition = FormStartPosition.Manual;

                this.Location = new Point(SystemInformation.VirtualScreen.Right + 10, SystemInformation.VirtualScreen.Bottom + 10);

                this.Size = new Size(1, 1);
            }
        }

        #region Form Events

        /// <summary>
        /// Checks the mail and start the timers for periodic checking.
        /// It then raises the <see cref="Form.Load"/> event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            this.CheckMail(true);

            this.checkMailTimer.Start();

            base.OnLoad(e);
        }

        /// <summary>
        /// Closes the form saving the stored credentials for future use.
        /// It then raises the <see cref="Form.Closing"/> event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosing(CancelEventArgs e)
        {
            this._credentialsManager.SaveCredentials();

            base.OnClosing(e);
        }

        #endregion

        #region Event Handlers

        private void checkMailMenuItem_Click(object sender, EventArgs e)
        {
            this.checkMailTimer.Stop();

            this.CheckMail(true);

            this.checkMailTimer.Start();
        }

        private void checkMailTimer_Tick(object sender, EventArgs e)
        {
            this.CheckMail(false);
        }

        private void exitMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void trayNotifyIcon_DoubleClick(object sender, EventArgs e)
        {
            BrowseGmail();
        }

        private void GmailManager_AuthenticationSucceeded(object sender, AuthenticationSucceededEventArgs e)
        {
            this._credentialsManager.SaveCredentials();
        }

        private void GmailManager_AuthenticationFailed(object sender, AuthenticationFailedEventArgs e)
        {
            NetworkCredential credential = null;

            e.Cancel = TryGetCredential(e.NewCredential.UserName, out credential);

            this._credentialsManager.AddOrUpdateCredentials(credential);

            e.NewCredential = credential;
        }

        #endregion

        #region Private Methods

        private static void BrowseGmail()
        {
            ThreadPool.QueueUserWorkItem(state =>
                {
                    Process.Start(Constants.Urls.GmailUrl);
                });
        }

        private void CheckMail(bool forceShowToast)
        {
            if (!this._isCheckMailInProgress)
            {
                this._isCheckMailInProgress = true;

                ThreadPool.QueueUserWorkItem(state =>
                    {
                        this.EnsureCredentialsAvailable();

                        var credentials = this._credentialsManager.Credentials;

                        int totalUnreadEmails = 0;

                        foreach (var credential in credentials)
                        {
                            AccountStatus status = GetAccountStatus(credential, forceShowToast);

                            if (status != null)
                            {
                                totalUnreadEmails += status.UnreadCount;

                                if ((status.UnreadCount > 0 && status.IsModified) || forceShowToast)
                                {
                                    this.ShowToast(status.UnreadCount);
                                }
                            }
                        }

                        this.UpdateMailCount(totalUnreadEmails);
                    });

                this._isCheckMailInProgress = false;
            }
        }

        private void ShowToast(int unreadCount)
        {
            string notificationMessage = unreadCount == 0
                ? Resources.DESKTOP_MSG_TOAST_NO_UNREAD_EMAILS
                : Resources.DESKTOP_MSG_TOAST_UNREAD_EMAILS.FormatWith(CultureInfo.CurrentUICulture, unreadCount);

            this._notificationManager.Toast.Notify(notificationMessage, NotificationSeverity.Information, this._toastActionHandler);
        }

        private AccountStatus GetAccountStatus(NetworkCredential credential, bool showTrayError)
        {
            AccountStatus status = null;

            try
            {
                status = this._gmailManager.GetAccountStatus(credential);
            }
            catch (WebException e)
            {
                string error = Resources.DESKTOP_ERR_UNABLE_TO_CONNECT_MESSAGE.FormatWith(e.Message);

                Logger.LogError(error);

                if (showTrayError)
                {
                    this._notificationManager.Tray.Notify(error, NotificationSeverity.Error);
                }
            }

            return status;
        }

        private void EnsureCredentialsAvailable()
        {
            var credentials = this._credentialsManager.Credentials;

            if (credentials.Count() == 0)
            {
                NetworkCredential credential = null;

                if (TryGetCredential(null, out credential))
                {
                    this._credentialsManager.AddOrUpdateCredentials(credential);
                }
            }
        }

        private static bool TryGetCredential(string userName, out NetworkCredential credential)
        {
            bool succeeded = false;

            credential = null;

            using (AuthenticationForm authForm = new AuthenticationForm(userName))
            {
                authForm.ShowDialog();

                if (authForm.DialogResult == DialogResult.OK)
                {
                    credential = authForm.Credentials;
                }
                else
                {
                    succeeded = false;
                }
            }

            return succeeded;
        }

        private void UpdateMailCount(int totalUnreadEmailCount)
        {
            int iconSuffix = totalUnreadEmailCount > 9 ? 10 : totalUnreadEmailCount;

            Icon trayIcon = (Icon)Resources.ResourceManager.GetObject("UnreadEmailTrayIcon_" + iconSuffix.ToString());

            this.trayNotifyIcon.Icon = trayIcon;
        }

        #endregion
    }
}
